package mornd.test2;

import mornd.test1.Bean1;
import mornd.test1.Bean2;
import mornd.test1.Bean3;
import mornd.test1.Bean5;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.annotation.InjectionMetadata;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.env.StandardEnvironment;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @author: mornd
 * @dateTime: 2023/5/4 - 20:41
 */
public class AutowiredAnnotationPostProcessorTest {

    public static void main(String[] args) throws Throwable {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        beanFactory.registerSingleton("bean2", new Bean2());
        beanFactory.registerSingleton("bean3", new Bean3());
        beanFactory.registerSingleton("bean5", new Bean5());

        beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        // 解析 spEL 表达式 ${}
        beanFactory.addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders);

        AutowiredAnnotationBeanPostProcessor annotationBeanPostProcessor = new AutowiredAnnotationBeanPostProcessor();
        annotationBeanPostProcessor.setBeanFactory(beanFactory);

        Bean1 bean1 = new Bean1();

        System.out.println(bean1);

        //customInject(annotationBeanPostProcessor, bean1);  //手动注入

        // 该方法正式处理 @Autowired @Value
        //annotationBeanPostProcessor.postProcessProperties(null, bean1, "bean1");
        /*
        @Value生效，${JAVA_HOME}
        @Autowired生效，mornd.test1.Bean2@52a86356
        Bean1[bean2=mornd.test1.Bean2@52a86356, bean3=null, name='${JAVA_HOME}']
         */

        System.out.println(bean1);

         // 属性
        Field f1 = Bean1.class.getDeclaredField("bean5");
        DependencyDescriptor dd1 = new DependencyDescriptor(f1, false);
        Bean5 bean5 = (Bean5) beanFactory.doResolveDependency(dd1,null,null,null);
        System.out.println(bean5);

        // 方法
        Method m1 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);
        DependencyDescriptor dd2 = new DependencyDescriptor(new MethodParameter(m1, 0), true);
        Bean2 bean2 = (Bean2) beanFactory.doResolveDependency(dd2, null, null, null);
        System.out.println(bean2);

        Method m2 = Bean1.class.getDeclaredMethod("setName", String.class);
        DependencyDescriptor dd3 = new DependencyDescriptor(new MethodParameter(m2, 0), false);
        String name = (String) beanFactory.doResolveDependency(dd3,null,null,null);
        System.out.println(name);
    }

    /**
     * 该方法会对 bean 中标注 @Autowired @Value  的属性或者方法做如下操作：
     * 属性：注入属性值，值从 beanFactory 中获取
     * 方法：调用方法，方法参数从 beanFactory 中获取
     * @param beanPostProcessor 后处理器
     * @param bean1
     * @throws Throwable
     */
    private static void customInject(BeanPostProcessor beanPostProcessor,
                                     Bean1 bean1) throws Throwable {
        Method method =
                AutowiredAnnotationBeanPostProcessor.class.getDeclaredMethod("findAutowiringMetadata", String.class, Class.class, PropertyValues.class);
        method.setAccessible(true);

        InjectionMetadata metadata =
                (InjectionMetadata) method.invoke(beanPostProcessor, "bean1", Bean1.class, null);

        metadata.inject(bean1, "bean1", null);
    }
}
